﻿using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BarcodePrint
{
    public static class PrintUtil
    {
        public static PrintWithTCP TCPConnect(DeviceType CurrentDeviceType = DeviceType.COM, string CurrentPrintParam = null, int TCPSendReceiveTimeout = 60)
        {
            if (CurrentDeviceType == DeviceType.TCP)
            {
                string[] values = CurrentPrintParam.Split(':');
                return new PrintWithTCP(values[0], int.Parse(values[1]), TCPSendReceiveTimeout);
            }
            return null;
        }


        public static void Print(string cmd, DeviceType deviceType, string printParam, int tcpSendReceiveTimeout = 60)
        {
            Action actionForLPT = () =>
            {
                PrintWithLPT lpt = new PrintWithLPT() { Port = int.Parse(printParam) };
                lpt.Print(cmd);
            };

            Action actionForTCP = () =>
            {
                string[] values = printParam.Split(':');
                PrintWithTCP tcp = new PrintWithTCP(values[0], int.Parse(values[1]), tcpSendReceiveTimeout);
                tcp.Print(cmd);
            };

            Action actionForDRV = () =>
            {
                PrintWithDriver drv = new PrintWithDriver(printParam);
                drv.Print(cmd);
            };

            Action actionForCOM = () =>
            {
                PrintWithCOM com = new PrintWithCOM() { Port = int.Parse(printParam) };
                com.Print(cmd);
            };

            switch (deviceType)
            {
                case DeviceType.LPT: actionForLPT.Invoke(); break;
                case DeviceType.TCP: actionForTCP.Invoke(); break;
                case DeviceType.DRV: actionForDRV.Invoke(); break;
                case DeviceType.COM: actionForCOM.Invoke(); break;
            }
        }
        public static void Print(byte[] cmd, DeviceType deviceType, string printParam, int tcpSendReceiveTimeout = 60)
        {
            Action actionForLPT = () =>
            {
                PrintWithLPT lpt = new PrintWithLPT() { Port = int.Parse(printParam) };
                lpt.Print(cmd);
            };

            Action actionForTCP = () =>
            {
                string[] values = printParam.Split(':');
                PrintWithTCP tcp = new PrintWithTCP(values[0], int.Parse(values[1]), tcpSendReceiveTimeout);
                tcp.Print(cmd);
            };

            Action actionForDRV = () =>
            {
                PrintWithDriver drv = new PrintWithDriver(printParam);
                drv.Print(cmd);
            };

            Action actionForCOM = () =>
            {
                PrintWithCOM com = new PrintWithCOM() { Port = int.Parse(printParam) };
                com.Print(cmd);
            };

            switch (deviceType)
            {
                case DeviceType.LPT: actionForLPT.Invoke(); break;
                case DeviceType.TCP: actionForTCP.Invoke(); break;
                case DeviceType.DRV: actionForDRV.Invoke(); break;
                case DeviceType.COM: actionForCOM.Invoke(); break;
            }
        }

        private static void Print(byte[] cmd, PrintWithTCP tcp)
        {
            tcp.Send(cmd);
        }

        private static void Print(string cmd, PrintWithTCP tcp)
        {
            Print(Encoding.Default.GetBytes(cmd), tcp);
        }

        private static PrinterStatus GetPrinterStatus(PrintWithTCP tcp)
        {
            byte[] bytes = new byte[82];
            PrinterStatus ps = new PrinterStatus();
            tcp.BeginConnect();
            tcp.Send(Encoding.Default.GetBytes("~HS"));
            tcp.Receive(bytes);
            string s = Encoding.ASCII.GetString(bytes);

            using (StringReader sr = new StringReader(s))
            {
                // consult the guide book
                string[] s1 = sr.ReadLine().TrimStart((char)2).TrimEnd((char)3).Split(',');
                string[] s2 = sr.ReadLine().TrimStart((char)2).TrimEnd((char)3).Split(',');
                ps.IsPaperOut = s1[1] == "1";
                ps.IsPause = s1[2] == "1";
                ps.Page = int.Parse(s2[8]);
            }
            tcp.EndConnect();

            return ps;
        }
    }


    public class PrinterStatus
    {
        /// <summary>
        /// 暂停
        /// </summary>
        public bool IsPause { get; set; }

        /// <summary>
        /// 缺纸
        /// </summary>
        public bool IsPaperOut { get; set; }

        /// <summary>
        /// 当前打印页码
        /// </summary>
        public int Page { get; set; }
    }
}
